<!DOCTYPE html>
<html>
<head>
	<title>ol-ext: Delaunay triangulation</title>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

	<meta name="description" content="Calculate the Delaunay triangulation of a Point vector source." />
	<meta name="keywords" content="ol, openlayers tirangulation, delaunay" />

	<!-- jQuery -->
	<script type="text/javascript" src="https://code.jquery.com/jquery-1.11.0.min.js"></script>

	<!-- Openlayers -->
  <link rel="stylesheet" href="https://openlayers.org/en/latest/css/ol.css" />
	<script type="text/javascript" src="https://openlayers.org/en/latest/build/ol.js"></script>
  <script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=requestAnimationFrame,Element.prototype.classList,URL"></script>
	
	<!-- ol-ext -->
  <link rel="stylesheet" href="../../dist/ol-ext.css" />
	<script type="text/javascript" src="../../dist/ol-ext.js"></script>

  <link rel="stylesheet" href="../style.css" />
  
  <style>
    .ol-control.ol-bar .ol-control.ol-text-button:hover {
      background: #33669977;
    }
    .ol-control.ol-bar .ol-control.ol-text-button.ol-active {
      background: #369;
    }
    .ol-control.ol-bar .ol-control.ol-text-button.ol-active > div,
    .ol-control.ol-bar .ol-control.ol-text-button > div:hover {
      color: #fff;
    }    
  </style>
</head>
<body >
  <a href="https://github.com/Viglino/ol-ext" class="icss-github-corner"><i></i></a>

	<a href="../../index.html">
		<h1>ol-ext: Delaunay triangulation</h1>
	</a>
	<div class="info">
    <p>
        The <i>ol/source/Delaunay</i> computes a 
        <a href="https://en.wikipedia.org/wiki/Delaunay_triangulation">
          Delaunay triangulation
        </a> 
        of a vector source (points).
    </p>
    <p>
      <span class="experimental">Experimental</span>
      this feature is still in progress and may be buggy.
    </p>
    <p>
      NB: the algorithm is incremental and not very efficient but it computes the triangulation directly in a <i>ol/source/Vector</i>. 
      <br/>
      You can add/remove vertex from the point source and get the resulting triangles directly in the triangle source.
      <br/>
      If you're looking for you'd better see an other algorithme like 
      <a href="https://github.com/mapbox/delaunator#performance">
        mapbox/delaunator
      </a>
    </p>
    <p>
      This is more to use with interactive processes to maintains a triangulation on state while interacting.
    </p>
	</div>

	<!-- Map div -->
	<div id="map" style="width:600px; height:400px;"></div>
	
	<div class="options">
    <input type="number" value="20" />
    <button onclick="generate(Number($(this).prev().val()))">Generate!</button>
    <br/>
    Generated triangles
    <ul class='triangles'></ul>
	</div>

<script type="text/javascript">

  function generate(nb)  {
    var t = new Date();
    var ext = map.getView().calculateExtent(map.getSize());
    for (var i=0; i<nb; ++i) {
      var f = new ol.Feature(new ol.geom.Point([ext[0]+(ext[2]-ext[0])*Math.random(), ext[1]+(ext[3]-ext[1])*Math.random()]));
      nodes.addFeature(f);
    }
    console.log('Elapsed',((new Date())-t)/1000+'s');
  }

	// Base layers
	var stamen = new ol.layer.Tile({
    title: "Watercolor",
    baseLayer: true,
    source: new ol.source.Stamen({
      layer: 'watercolor'
    })
  });

	// The map
	var map = new ol.Map ({
    target: 'map',
    view: new ol.View ({
      zoom: 4,
      center: [205461, 5867916]
    }),
    layers: [stamen]
  });

  // Default style
	var fill = new ol.style.Fill({
		color: 'rgba(255,255,255,0.4)'
	});
	var stroke = new ol.style.Stroke({
		color: '#3399CC',
		width: 1.25
	});
	var style = new ol.style.Style({
		image: new ol.style.RegularShape({
			stroke: stroke,
			points: 4,
			radius: 5,
			radius2: 0
		}),
		text: new ol.style.Text({
      font: 'bold 10px sans-serif',
			text:'test',
			textAlign: 'left',
			textBaseline: 'bottom',
			offsetX: 3,
			offsetY: -3
		}),
		fill: fill,
		stroke: stroke
  });
  
  var redStyle = new ol.style.Style({
    fill: new ol.style.Fill({ color: [255,0,0,.2] })
  });

  // Node source
  var nodes = new ol.source.Vector();
  var nb = 0;
  nodes.on('addfeature', function(e) {
    e.feature.set('id', nb++);
  });
  var vector = new ol.layer.Vector({
    name: 'vector',
		source: nodes,
		style: function(f) {
			style.getText().setText(String(f.get('id')||'0'));
			return style;
		}
  });

  // Delaunay source based on the node source
  var delaunay = new ol.source.Delaunay({
	  source: nodes
  });
  var triangle = new ol.layer.Vector({
    name: 'triangle',
    source: delaunay
  });

  // In the map
  map.addLayer(triangle);
  map.addLayer(vector);

  // Control Bar
  var bar = new ol.control.Bar({ toggleOne: true });
  map.addControl(bar);

  // Draw interaction to add new points
  var draw = new ol.interaction.Draw({ source: nodes, type:"Point" });
  bar.addControl(new ol.control.Toggle({
    className: 'ol-text-button',
    html: "add",
    interaction: draw,
    active: true
  }));

  // Delete
	var del = new ol.interaction.Select({
    layers: [vector],
    hitTolerance: 5
  });
  del.on('select', function(e){
    var f = e.selected[0];
    if (f) nodes.removeFeature(f);
    del.getFeatures().clear();
  });
  bar.addControl(new ol.control.Toggle({
    className: 'ol-text-button',
    html: "del",
    interaction: del
  }));

/*
  // Draw interaction to add new points
  var modify = new ol.interaction.Modify({ source: nodes });
  bar.addControl(new ol.control.Toggle({
    className: 'ol-text-button',
    html: "mod",
    interaction: modify,
  }));
  modify.on('modifystart', function(e){
    console.log(e)
    var f = modify.dragSegments_[0][0].feature;
    //nodes.removeFeature(f)
  });
  modify.on('modifyend', function(e){
    console.log(e)
    var f = modify.dragSegments_[0][0].feature;
    //nodes.addFeature(f);
  });
*/

  // Select
  var circle = new ol.layer.Vector({
    name: 'circle',
    source: new ol.source.Vector(),
    style: redStyle
  });
  map.addLayer(circle);

  // Show circumcircle on hover
	var hover = new ol.interaction.Hover({
    layers: [triangle]
  });
  hover.on('enter', function(e){
    circle.getSource().clear();
    if (e.layer===triangle) {
      var c = e.feature.getGeometry().getCoordinates()[0];
      c = delaunay.getCircumCircle(c);
      if (c.radius) {
        c = new ol.geom.Circle(c.center, c.radius);
        var f = new ol.Feature(c);
        circle.getSource().addFeature(f);
      }
    }
  });
  hover.on('leave', function(e){
    circle.getSource().clear();
  });
	bar.addControl(new ol.control.Toggle({
    className: 'ol-text-button',
    html: 'circle',
    interaction: hover
  }));

</script>
	
</body>
</html>